import type { ActivedOptionNames, ProgramController, ProgramGroupConfig } from './definition'
import type { BaseController } from '@/controller/BaseAppliance/definition'
import type { Option } from '@/pages/appliance/components/parameterCard.vue'
import {
  selectProgram,
  getApplianceProgramList,
  getProgramAvailableScope,
  startNow,
  abortProgram,
  orderNow,
  pauseProgram,
  resumeProgram,
  getApplianceHistoryProgramList,
  HistoryProgramTypes,
  type ApplianceProgram,
  type ProgramSelectOption,
  type HistoryProgramOption,
  type ProgramAvailable,
  getProgramSelectedOptions,
  type ProgramSelectedScope,
  adjustProgramOptions,
  type ApplianceDetailOption,
} from '@/api/appliance'
import {
  START_IN_RELATIVE,
  FINISH_IN_RELATIVE,
  SELECTED_PROGRAM,
  REMAINING_PROGRAM_TIME,
  OPERATION_KEY,
  OPERATION_STATES,
  PROGRAM_PROGRESS,
  OPERATION_PAUSE_PROGRAM,
  OPERATION_STOP_PROGRAM,
  ESTIMATED_TOTAL_PROGRAM_TIME,
  OPERATION_RESUME_PROGRAM,
  REMOTE_CONTROL_ACTIVE,
  REMOTE_CONTROL_START_ALLOWED,
  LOCAL_CONTROL_ACTIVE,
  BSH_COMMOM_PROGRAM_FAVORITE_001,
  BSH_COMMOM_PROGRAM_FAVORITE_002,
  BSH_COMMON_OPTION_PROGRAMNAME,
  BSH_COMMON_OPRION_BASEPROGRAM,
  DURATION,
} from '@/constants/Command'
import i18n from '@/i18n'
import { actionDebounce, showLoading } from '@/utils/mpHelper'
import type { Remote } from '@/controller/base/types/remote'
import { debounce } from 'lodash'
import { filterFavoritePrograms, getSettingsFavorite } from '@/controller/common/Program/FavoriteHelper'
import { TrackType, trackEvent } from '@/dataReport/tracks'
import { useControlState, useStatements } from '@/controller/BaseAppliance/useControl'
import { safeTrack } from '@/dataReport/dataReportUtil'
import { getTimeTextByDuration } from '@/utils/timeUtils'
import { useAccountStore } from '@/store/account'
import { generalUnitFormatter } from '@/pages/appliance/view/availableParameterUtils'

const ALL_PROGRAMS_GROUP = 'ALL_PROGRAMS_GROUP'
type TrackData = {
  program_key: string
  error_code: number | string
  response_msg: number | string
  [key: string]: unknown
}

export const createProgramState: () => ProgramController.PureState = () => ({
  // 程序
  currentProgramGroupKey: ALL_PROGRAMS_GROUP,
  allPrograms: null,
  currentProgramKey: '',
  // 最近程序
  usingHistoryPrograms: false, // 默认不启用最近程序
  historyPrograms: null,
  // 程序状态
  programPauseSupported: true, // 程序支持暂停
  programResumeSupported: true, // 程序支持继续
  programAbortSupported: true, // 程序支持终止
  programStartedByClient: false,
  // 调节参数
  availableParameter: null,
  selectedProgramOptions: null,
  programOrderAllowed: false,
  programRemaining: 0,
  programRemainingText: '', // 程序剩余时间显示 格式: 0小时0分钟
  programRelativeLoading: false, // 正在加载程序预约信息 (用于切换程序后标记detail、available的加载是否完成)
  programStartTime: 0,
  programEndTime: 0,
})

export const ProgramGetters: ProgramController.Getters = {
  // 默认不启用分组功能，需自行配置
  programGroupsConfig() {
    return null
  },
  programGroups() {
    return getProgramGroups(this.programGroupsConfig, this.customizedAllPrograms).concat(this.favoriteGroups)
  },
  currentProgramGroup() {
    if (!this.programGroups.length) return null
    if (this.programGroups.length === 1) return this.programGroups[0]
    return this.programGroups.find((group) => group.key === this.currentProgramGroupKey) || null
  },
  orderProgramGroups() {
    return getProgramGroups(this.programGroupsConfig, this.customizedOrderAllPrograms).concat(this.favoriteGroups)
  },
  currentOrderProgramGroup() {
    if (!this.orderProgramGroups.length) return null
    if (this.orderProgramGroups.length === 1) return this.orderProgramGroups[0]
    return this.orderProgramGroups.find((group) => group.key === this.currentProgramGroupKey) || null
  },
  customizedAllPrograms() {
    // 过滤收藏程序
    if (!this.favoriteForceDisabled && this.hasFavoriteFunction) {
      return filterFavoritePrograms(this.allPrograms || [])
    } else {
      return this.allPrograms || []
    }
  },
  customizedOrderAllPrograms() {
    return this.customizedAllPrograms
  },
  // 收藏分组
  favoriteGroups() {
    if (!Array.isArray(this.favoriteProgramsList)) return []

    return [
      {
        key: 'Program.Favorite',
        name: i18n.global.t('Appliance.ProgramGroup.MyFavorite.Text'),
        programs: this.favoriteProgramsList,
      },
    ]
  },
  // 是否强制禁用收藏程序
  favoriteForceDisabled() {
    return false
  },
  hasFavoriteFunction() {
    const hasFavorite = this._datasource.settings.some((setting) => {
      const sortKey = setting.key.replace(/^BSH\.Common\.Setting\.Favorite\.(\d+)\.(\S+)$/, '$1')
      return setting.key.startsWith('BSH.Common.Setting.Favorite') && setting.key.endsWith(`${sortKey}.Functionality`)
    })
    return hasFavorite
  },
  favoriteProgramsList() {
    if (this.favoriteForceDisabled || !this.hasFavoriteFunction) return null
    const favoriteSettings = getSettingsFavorite(this._datasource.settings).filter((item) => item.collect)

    return (this.allPrograms || []).reduce((favoriteProgramsList: ApplianceProgram.Scope[], program) => {
      if (program.key.indexOf('Program.Favorite') !== -1) {
        // BSH.Common.Program.Favorite.001
        if (program.key.match(/^BSH\.Common\.Program\.Favorite\.(\d+)$/)) {
          const programKey = program.key.replace(/^BSH\.Common\.Program\.Favorite\.(\d+)$/, '$1')
          favoriteSettings.forEach((settingFavorite) => {
            if (settingFavorite.favoriteIndex === programKey && settingFavorite.collect) {
              if (settingFavorite.name) {
                program.name = settingFavorite.name
                program.baseProgramKey = settingFavorite.baseProgramKey
              }

              favoriteProgramsList.push(program)
            }
          })
        }
      }
      return favoriteProgramsList
    }, [])
  },
  programs() {
    if (!this.currentProgramGroup) return []
    return this.currentProgramGroup.programs
  },
  orderPrograms() {
    if (!this.currentOrderProgramGroup) return []
    return this.currentOrderProgramGroup.programs
  },
  currentProgram() {
    return this.allPrograms?.find((program) => program.key === this.currentProgramKey) || null
  },
  currentProgramName() {
    return this.currentProgram?.name || this._datasource.detail?.programName || ''
  },

  // 最近启用的程序
  recentStartedPrograms() {
    return (this.historyPrograms || []).filter((history) => history.programType === HistoryProgramTypes.StartedProgram)
  },
  // 最近预约的程序
  recentOrderedPrograms() {
    return (this.historyPrograms || []).filter((history) => history.programType === HistoryProgramTypes.OrderedProgram)
  },

  // RELATIVE 选项 (用于判断预约)
  orderRelativeOption() {
    const relativeOption = this.availableParameter?.options?.find((option) =>
      [START_IN_RELATIVE, FINISH_IN_RELATIVE].includes(option.key)
    ) as ProgramAvailable.IntegerOption | undefined
    return relativeOption || null
  },

  // 刷新数据延迟时间
  refreshDelayTime() {
    return 0
  },
  // 刷新剩余时间的防抖时间
  remainingDebouncedTime() {
    return 0
  },
  // 刷新detail时同步刷新commands
  syncCommandsWhileDetailLoading() {
    return true
  },
  // 是否强制隐藏暂停程序按钮
  hidePauseForced() {
    return false
  },
  // 是否检查启动时间在谷电时间相近范围内
  shouldCheckValleyTimeApproching() {
    return false
  },
  // 当前状态下是否可调节参数
  isAdjustableOperationState() {
    return [
      OPERATION_STATES.READY,
      OPERATION_STATES.RUN,
      OPERATION_STATES.DELAYED_START,
      OPERATION_STATES.PAUSE,
    ].includes(this.operationState as OPERATION_STATES)
  },
  // 需要忽略的调节参数Key
  ignoredOptionKeys() {
    return [START_IN_RELATIVE, FINISH_IN_RELATIVE, ESTIMATED_TOTAL_PROGRAM_TIME, DURATION].concat(
      this.customIgnoredOptionKeys
    )
  },
  // 需要忽略显示的参数Key
  ignoredDisplayOptionKeys() {
    return [
      START_IN_RELATIVE,
      FINISH_IN_RELATIVE,
      ESTIMATED_TOTAL_PROGRAM_TIME,
      DURATION,
      // 收藏程序
      BSH_COMMOM_PROGRAM_FAVORITE_001,
      BSH_COMMOM_PROGRAM_FAVORITE_002,
      BSH_COMMON_OPTION_PROGRAMNAME,
      BSH_COMMON_OPRION_BASEPROGRAM,
    ].concat(this.customIgnoredDisplayOptionKeys)
  },
  customIgnoredOptionKeys() {
    return []
  },
  customIgnoredDisplayOptionKeys() {
    return this.customIgnoredOptionKeys
  },
  activedOptionNames() {
    const selectedOptions = this.selectedProgramOptions?.options
    if (!Array.isArray(selectedOptions)) return []

    return selectedOptions.reduce<ActivedOptionNames[]>((names, option) => {
      if (this.ignoredDisplayOptionKeys.includes(option.key)) return names

      putValidOption(names, option, (this as ProgramController.Store).customDisplayOptionFormatter)
      return names
    }, [])
  },
  // 可调节的参数选项
  adjustableOptions() {
    // 过滤当前available 去除需要忽略的参数
    const availableOptions = (this.availableParameter?.options || []).filter(
      (option) => !this.ignoredOptionKeys.includes(option.key)
    )
    return availableOptions
  },
  runAvailableDisabled() {
    return false
  },
  runSelectedDisabled() {
    return false
  },
  // 是否强制将【预计xx:xx结束】转换为【预计xx:xx开始】(无programRemaining时会显示【正在计算】)
  transformRelativeOrderForced() {
    return false
  },
}

export const ProgramActions: ProgramController.FragmentActions = {
  loadAllPrograms: actionDebounce<ProgramController.Store>({
    timeout: null,
    async call() {
      const res = await getApplianceProgramList(this._datasource.haId)
      this.allPrograms = res.data.programs || null
    },
  }),
  loadHistoryPrograms: actionDebounce<ProgramController.Store>({
    timeout: null,
    async call() {
      const res = await getApplianceHistoryProgramList(this._datasource.haId)
      this.historyPrograms = res.data || []
    },
  }),
  loadAvailableParameter: actionDebounce<ProgramController.Store>({
    timeout: null,
    async call() {
      if (!this.currentProgramKey) return
      const res = await getProgramAvailableScope(this._datasource.haId, this.currentProgramKey)
      this.availableParameter = res.data
    },
  }),
  loadSelectedOptions: actionDebounce<ProgramController.Store>({
    timeout: null,
    async call() {
      if (this.runSelectedDisabled) return
      const res = await getProgramSelectedOptions(this._datasource.haId)
      this.selectedProgramOptions = res.data
    },
  }),
  async setCurrentProgramGroup(group: ApplianceProgram.Group | string) {
    const groupKey = typeof group === 'string' ? group : group.key
    this.currentProgramGroupKey = groupKey
  },
  setCurrentProgram: actionDebounce<ProgramController.Store>({
    timeout: null,
    loadingText: i18n.global.t('APP.Common.Submitting.Text'),
    async call(program: ApplianceProgram.Scope | string, options?: ProgramSelectOption[]) {
      const programKey = typeof program === 'string' ? program : program.key
      const programName = typeof program === 'string' ? program : program.name
      // 切换程序时 重置程序时长 待ws推送新的程序时长
      this.programRemaining = 0

      let res: any = null
      try {
        res = await selectProgram(this._datasource.haId, programKey, options)
      } catch (error) {
        res = error
      } finally {
        // 数据埋点
        if (options) {
          safeTrack(() => {
            const optionKey = options[0].key
            const optionName = options[0].value
            trackEvent(
              'select_option',
              {
                program_key: programKey,
                program_name: programName,
                select_option_key: optionKey,
                select_option_value: optionName,
                successOrNot: res.code == 0,
                error_code: res.code,
                response_msg: res.msg,
              },
              TrackType.ApplianceDetail
            )
          })
        } else {
          safeTrack(() => {
            let programeTrackData = {
              program_key: programKey,
              program_name: programName,
              successOrNot: res.code == 0,
              error_code: res.code,
              response_msg: res.msg,
            }
            trackEvent(
              'select_program',
              programeTrackData,
              TrackType.ApplianceDetail,
              'Appliance.Detail.Select.Program'
            )
          })
        }
      }
    },
  }),
  selectProgramOptions: actionDebounce<ProgramController.Store>({
    timeout: null,
    loadingText: i18n.global.t('APP.Common.Submitting.Text'),
    async call(options: ProgramSelectOption[], programKey, programName) {
      if (!this.currentProgramKey) return
      const { showControlView } = useStatements(this as BaseController.Store)
      let res: any = null
      try {
        if (showControlView.value) {
          res = await selectProgram(this._datasource.haId, this.currentProgramKey, options)
        } else {
          res = await adjustProgramOptions(this._datasource.haId, options)
        }
      } catch (error) {
        res = error
      } finally {
        trackEvent(
          'select_option',
          {
            program_key: programKey,
            program_name: programName,
            select_option_key: options[0].key,
            select_option_value: options[0].value,
            successOrNot: res.code == 0,
            error_code: res.code,
            response_msg: res.msg,
          },
          TrackType.ApplianceDetail
        )
      }
    },
  }),
  customDisplayOptionFormatter: () => null,
  orderProgramNow: actionDebounce<ProgramController.Store>({
    timeout: null,
    delay: 3000,
    async call(program: ApplianceProgram.Scope, options: ProgramSelectOption[], trackData: any) {
      const validOptions = getValidProgramOptions(options)
      let res: any = null

      try {
        res = await showLoading(
          () => orderNow(this._datasource.haId, program, validOptions),
          i18n.global.t('Appliance.OrderProgram.Ordering.Text')
        )

        uni.showToast({
          title: i18n.global.t('Appliance.OrderProgram.OrderSuccess.Text'),
          duration: 3000,
          mask: true,
        })
      } catch (error) {
        res = error
      } finally {
        safeTrack(() => {
          trackData['successOrNot'] = res.code == 0
          trackData['error_code'] = res.code
          trackData['response_msg'] = res.msg
          trackEvent('reserve_program', trackData, TrackType.ApplianceDetail)
        })
      }
      this.programStartedByClient = true
    },
  }),

  // 立即启动
  startProgramNow: actionDebounce<ProgramController.Store>({
    timeout: null,
    delay: 3000,
    loadingText: i18n.global.t('APP.Common.Submitting.Text'),
    async call(
      program: ApplianceProgram.Scope,
      options?: ProgramSelectOption[],
      buttonId?: string,
      customTrack?: boolean
    ) {
      const validOptions = getValidProgramOptions(options)
      let res: any = null
      try {
        res = await startNow(this._datasource.haId, program, validOptions)
      } catch (error) {
        res = error
      } finally {
        if (!customTrack) {
          safeTrack(() => {
            // 立即启动埋点处理
            const trackData: TrackData = {
              program_key: '',
              program_name: '',
              successOrNot: res.code == 0,
              error_code: res.code,
              response_msg: res.msg,
            }
            let DataArry: ProgramSelectOption[] = []
            validOptions.map((items) => {
              DataArry.push(items)
            })
            trackData.program_key = program.key || ''
            trackData.program_name = program.trackName || program.name || ''
            if (DataArry.length > 0) {
              DataArry.map((items, index) => {
                trackData[`option_obj_${index + 1}`] = items
              })
            }
            trackEvent('start_program', trackData, TrackType.ApplianceDetail, buttonId)
          })
        }
        this.programStartedByClient = true
      }
    },
  }),
  async abortProgram(trackData?: any, isReserve?: boolean) {
    return showLoading(async () => {
      let res: any = null
      try {
        res = await abortProgram(this._datasource.haId)
      } catch (error) {
        res = error
      } finally {
        safeTrack(() => {
          trackData['successOrNot'] = res.code == 0
          trackData['error_code'] = res.code
          trackData['response_msg'] = res.msg
          if (isReserve) {
            // 取消预约
            trackEvent(
              'cancel_reserve_program',
              trackData,
              TrackType.ApplianceDetail,
              'Appliance.StateView.Abort.Button.Text'
            )
          } else {
            // 停止程序
            trackEvent('stop_program', trackData, TrackType.ApplianceDetail, 'Appliance.StateView.Abort.Button.Text')
          }
        })
      }
    }, i18n.global.t('APP.Common.Submitting.Text'))
  },
  async pauseProgram(trackData?: any) {
    return showLoading(async () => {
      let res: any = null
      try {
        res = await pauseProgram(this._datasource.haId)
      } catch (error) {
        res = error
      } finally {
        safeTrack(() => {
          trackData['successOrNot'] = res.code == 0
          trackData['error_code'] = res.code
          trackData['response_msg'] = res.msg
          trackEvent('pause_program', trackData, TrackType.ApplianceDetail, 'Appliance.StateView.Pause.Button.Text')
        })
      }
    }, i18n.global.t('APP.Common.Submitting.Text'))
  },
  async resumeProgram(trackData?: any) {
    return showLoading(async () => {
      let res: any = null
      try {
        res = await resumeProgram(this._datasource.haId)
      } catch (error) {
        res = error
      } finally {
        safeTrack(() => {
          trackData['successOrNot'] = res.code == 0
          trackData['error_code'] = res.code
          trackData['response_msg'] = res.msg
          trackEvent('resume_program', trackData, TrackType.ApplianceDetail, 'Appliance.StateView.Resume.Button.Text')
        })
      }
    }, i18n.global.t('APP.Common.Submitting.Text'))
  },
}

/**
 * 远程控制/远程启动/本地操作 变化时 刷新available
 */
export const RemoteChangeOrderObserve: Remote.BatchObserve<ProgramController.Store> = {
  matcher: (msg) => [REMOTE_CONTROL_ACTIVE, REMOTE_CONTROL_START_ALLOWED, LOCAL_CONTROL_ACTIVE].includes(msg.key),
  handler: debounce((_, remote) => {
    remote.store.loadAvailableParameter()
  }, 500),
}

export const SelectOptionsObserve: Remote.BatchObserve<ProgramController.Store> = {
  matcher: (msg) => msg.key.includes('Option') && !OptionIgnoreList.includes(msg.key),
  handler: actionDebounce({
    async call(_, remote) {
      /**
       * 运行中切换Option时
       *  - 刷新detail 获取最新的预计结束时间
       *  - 刷新selectedOptions 获取最新已选中的Options
       */
      await Promise.all([remote.loadApplianceDetail(), remote.store.loadSelectedOptions()])
    },
  }),
}

/**
 * option批量消息监听
 */
const OptionIgnoreList = [START_IN_RELATIVE, FINISH_IN_RELATIVE, PROGRAM_PROGRESS, REMAINING_PROGRAM_TIME]
export const OptionBatchObserve: Remote.BatchObserve<ProgramController.Store> = {
  matcher: (msg) => msg.key === SELECTED_PROGRAM || (msg.key.includes('Option') && !OptionIgnoreList.includes(msg.key)),
  handler: debounce(async (_, remote: Remote.ApplianceRemote<ProgramController.Store>) => {
    const tasks = [
      // 切换option后刷新detail查询option选择状态、程序时长等数据
      remote.loadApplianceDetail(),
    ]
    // 同时查询commands
    if (remote.store.syncCommandsWhileDetailLoading) {
      tasks.push(remote.loadSupportCommands())
    }
    await Promise.all(tasks)

    // 加载调节参数配置
    // 在调用detail后加载，防止由于监听availableParameter并取值detailOption后，出现取到的detailOption旧值的情况
    remote.store.loadAvailableParameter()
  }, 500),
}

/**
 * 消息监听
 */
const ProgramObserve: Remote.Observe<ProgramController.Store> = {
  [SELECTED_PROGRAM](_, remote) {
    const { showControlView } = useStatements(remote.store as BaseController.Store)
    if (!showControlView.value) return

    // 标记RelativeOption正在加载
    remote.store.programRelativeLoading = true
    setTimeout(async () => {
      try {
        const tasks = []
        // 选择程序时调用详情接口
        tasks.push(remote.loadApplianceDetail())
        // 同时查询commands
        if (remote.store.syncCommandsWhileDetailLoading) {
          tasks.push(remote.loadSupportCommands())
        }

        /**
         * 切换程序 刷新available数据
         *  - 用于预约页面切换程序后进入【调节参数】显示正确内容
         *  - 用于详情页点击【立即启动】时判断谷电时间跳转
         */
        tasks.push(remote.store.loadAvailableParameter())

        await Promise.all(tasks)
      } catch (e) {
        console.error(e)
      } finally {
        remote.store.programRelativeLoading = false
      }
    }, remote.store.refreshDelayTime)
  },
  [OPERATION_KEY](msg, remote) {
    // 重置available
    remote.store.availableParameter = null

    setTimeout(() => {
      // 用于获取预约时间、预约时长、运行时间 等
      remote.loadApplianceDetail()
      // 切换状态时，支持的commands会变化 需要刷新commands 查询是否支持暂停等
      remote.loadSupportCommands()
    }, remote.store.refreshDelayTime)

    switch (msg.value) {
      case OPERATION_STATES.RUN:
      case OPERATION_STATES.DELAYED_START:
      case OPERATION_STATES.PAUSE: {
        // 查询已选中的参数
        remote.store.loadSelectedOptions()
        if (!remote.store.runAvailableDisabled) {
          // 查询可调节的参数
          setTimeout(() => {
            remote.store.loadAvailableParameter()
          }, remote.store.refreshDelayTime)
        }
        break
      }
      case OPERATION_STATES.ABORTING: {
        // 查询已选中的参数
        remote.store.loadSelectedOptions()
        break
      }
      case OPERATION_STATES.READY: {
        // 用于刷新程序列表
        setTimeout(() => {
          remote.store.loadAllPrograms()
          // remote.store.usingHistoryPrograms && remote.store.loadHistoryPrograms()
        }, 500)

        setTimeout(() => {
          /**
           * 刷新available数据
           *  - 用于判断是否可以预约、最近程序 需要过滤不支持的Option
           *  - 用于详情页点击【立即启动】时判断谷电时间跳转
           */
          remote.store.loadAvailableParameter()
        }, remote.store.refreshDelayTime)
        break
      }
      default: {
        break
      }
    }
  },
}
/**
 * 监听收藏添加和删除
 */
const FavoriteBatchObserve: Remote.BatchObserve<ProgramController.Store> = {
  matcher: (msg) =>
    /^BSH\.Common\.Setting\.Favorite\.(\d+)\.Functionality$/.test(msg.key) ||
    /^BSH\.Common\.Setting\.Favorite\.(\d+)\.Name$/.test(msg.key),
  handler() {
    this.loadAllSetting()
  },
}

export function useProgramEffects<Control extends BaseController.Control>(control: Control) {
  useProgramBinding(control)

  if (control.store.isVirtualAppliance) return

  const accountStore = useAccountStore()
  const { showControlView } = useControlState(control)
  control.worker.onLoad(async () => {
    const tasks: Promise<void>[] = []
    // 页面进入时 为列表页
    if (showControlView.value) {
      // 有选中的当前程序
      if (control.store.currentProgramKey) {
        /**
         * 加载available数据 (暂无需加入task 不涉及loading)
         *  - 用于预约页面切换程序后进入【调节参数】显示正确内容
         *  - 用于详情页点击【立即启动】时判断谷电时间跳转
         */
        control.store.loadAvailableParameter()
      }
      // 启用最近程序 加载列表
      // if (control.store.usingHistoryPrograms) {
      //   tasks.push(control.store.loadHistoryPrograms())
      // }
    }
    // 页面进入时 为运行状态
    else {
      // 刷新支持指令 [暂停/停止] 等
      tasks.push(control.remote.loadSupportCommands())
      /**
       * 加载Option数据
       */
      // 加载显示已选中Option
      tasks.push(control.store.loadSelectedOptions())
      if (!control.store.runAvailableDisabled) {
        // 加载available 用于调节运行中参数
        control.store.loadAvailableParameter()
      }
    }

    // 加载谷电时间设置 用于立即启动时检查谷电时间 (不加入等待列表)
    accountStore.loadValleyData()

    return Promise.all(tasks)
  })

  control.remote.addObserve(ProgramObserve)
  control.remote.addBatchObserve(FavoriteBatchObserve)
}

export function useProgramBinding<Control extends BaseController.Control>(control: Control) {
  const { store, worker } = control

  /**
   * 同步修改当前程序分组
   */
  watch(
    () => store.programGroups,
    (groups) => {
      const groupKey = getGroupKeyByActivedProgram(groups, store.currentProgramKey) || groups[0]?.key || null
      if (!groupKey) return
      store.currentProgramGroupKey = groupKey
    }
  )
  watch(
    () => store.currentProgramKey,
    (programKey) => {
      if (!programKey) return
      const groupKey = getGroupKeyByActivedProgram(store.programGroups, programKey)
      if (!groupKey) return
      store.currentProgramGroupKey = groupKey
    },
    {
      immediate: true,
    }
  )

  /**
   * 程序剩余时间处理
   */
  type RemainingSetter = (remaining: number) => void
  const setProgramRemaining: RemainingSetter = (remaining: number) => {
    store.programRemainingText = getTimeTextByDuration(remaining, { ceilToMinute: true, ceilZero: true })
  }
  // 程序剩余时间防抖处理
  let setProgramRemainingDebounced!: RemainingSetter
  watchEffect(() => {
    // 无需防抖时 直接设置
    if (store.remainingDebouncedTime === 0) {
      setProgramRemainingDebounced = setProgramRemaining
    }
    // 防抖处理
    else {
      setProgramRemainingDebounced = debounce(setProgramRemaining, store.remainingDebouncedTime)
    }
  })

  watch(
    () => store.programRemaining,
    (programRemaining) => {
      if (programRemaining === 0) {
        setProgramRemaining(programRemaining)
        return
      }

      // 值非0时 防抖设置剩余时间 防止出现精控强洗推送数次形成文字闪烁
      setProgramRemainingDebounced(programRemaining)
    },
    {
      immediate: true,
    }
  )

  // 虚拟家电不绑定数据
  if (store.isVirtualAppliance) return

  const { showControlView } = useControlState(control)
  // 视图切换时 判断是否清空缓存的已选择Option
  watch(
    () => showControlView.value,
    () => {
      // 清空已选中选项 等待查询
      store.selectedProgramOptions = null
    }
  )

  // 绑定当前程序Key
  worker.useGetValueBinding('currentProgramKey', {
    key: SELECTED_PROGRAM,
    from: 'event',
    useMessage: 'only',
    patcher(patchState, reference) {
      // 防止推送为null导致空串判断失效
      patchState.currentProgramKey = (reference.value as string | null) || ''
    },
  })
  worker.useDetailBinding('currentProgramKey', (detail) => {
    // 虚拟家电 且存在前一个程序 不再同步
    if ((control.store.isVirtualAppliance && control.store.currentProgramKey) || !detail.programKey) return void 0
    return detail.programKey
  })

  worker.useGetValueBinding('programStartTime', {
    key: START_IN_RELATIVE,
    from: 'event',
    useMessage: 'only',
  })
  worker.useGetValueBinding('programEndTime', {
    key: FINISH_IN_RELATIVE,
    from: 'event',
    useMessage: 'only',
  })

  // 当前程序是否支持暂停/继续/终止
  worker.useHasKeyBinding('programPauseSupported', {
    key: OPERATION_PAUSE_PROGRAM,
    from: 'command',
  })
  worker.useHasKeyBinding('programResumeSupported', {
    key: OPERATION_RESUME_PROGRAM,
    from: 'command',
  })
  worker.useHasKeyBinding('programAbortSupported', {
    key: OPERATION_STOP_PROGRAM,
    from: 'command',
  })

  // 当前程序是否可预约
  worker.useHasKeysBinding('programOrderAllowed', {
    keys: [START_IN_RELATIVE, FINISH_IN_RELATIVE],
    from: 'available',
    match: 'some',
  })

  worker.useGetValueBinding('programRemaining', {
    key: REMAINING_PROGRAM_TIME,
    from: 'detailOption',
  })
  worker.useDetailBinding('programRemaining', (detail) => {
    const remaining = detail.displayTimes?.remainingProgramTime as number
    if (typeof remaining === 'number') {
      return remaining
    }
  })
}

function getProgramGroups(
  groupConfigList: ProgramGroupConfig[] | null,
  allProgramList: ApplianceProgram.Scope[]
): ApplianceProgram.Group[] {
  if (!groupConfigList) {
    const allGroupPrograms = [
      {
        key: ALL_PROGRAMS_GROUP,
        name: i18n.global.t('Appliance.AllPrograms.Label.Text'),
        programs: allProgramList,
      },
    ]
    return allGroupPrograms
  }

  const groups: ApplianceProgram.Group[] = groupConfigList.map((groupConfig) => {
    const prefix = groupConfig.customPrefix || groupConfig.key
    return {
      key: groupConfig.key,
      name: groupConfig.name,
      programs: allProgramList.filter((program) => program.key.startsWith(prefix)) || [],
    }
  })
  const groupFilter = groups.filter((groupConfig) => groupConfig.programs.length > 0)
  return groupFilter
}

function getGroupKeyByActivedProgram(groups: ApplianceProgram.Group[], programKey: string): string | null {
  if (!programKey) return null
  return (
    groups.find((group) => {
      return group.programs.some((program) => program.key === programKey)
    })?.key || null
  )
}

export function getValidProgramOptions(
  options?: ProgramSelectOption[] | HistoryProgramOption[]
): ProgramSelectOption[] {
  return (options || []).map<ProgramSelectOption>((option) => {
    const validOption = Object.entries(option).reduce((validOption, [key, value]) => {
      if (!['displayvalue', 'unit'].includes(key)) {
        validOption[key] = value
      }
      return validOption
    }, {} as Record<string, any>) as ProgramSelectOption
    return validOption
  })
}

/**
 * 设置程序已选择参数的显示值
 */
export function putValidOption(
  list: ActivedOptionNames[],
  option: ProgramSelectOption | ApplianceDetailOption,
  customFormatter?: (option: ProgramSelectOption | ApplianceDetailOption) => ActivedOptionNames | null
): void {
  // 自定义设置方法
  if (typeof customFormatter === 'function') {
    const optionName = customFormatter(option)
    if (optionName) {
      list.push(optionName)
      return
    }
  }

  // 勾选类型
  if (typeof option.value === 'boolean') {
    if (option.value === true) {
      list.push({ key: option.key, label: option.name || '' })
    }
  }
  // 数字类型
  else if (typeof option.value === 'number') {
    // 单位后缀
    let unit = generalUnitFormatter(option.key, option.value, option.unit)
    // 数据处理
    let value = option.value
    if (unit === 'seconds' && value % 60 === 0) {
      value = value / 60
      unit = '分钟'
    }

    const suffix = unit ? ` ${unit}` : ''
    list.push({ key: option.key, label: option.name || '', value: `${value}${suffix}` })
  }
  // 枚举类型
  else if (typeof option.value === 'string' && option.displayvalue && !option.value.includes('.Off')) {
    // 单位后缀
    const unit = generalUnitFormatter(option.key, option.value, option.unit)
    const suffix = unit ? ` ${unit}` : ''
    list.push({ key: option.key, label: option.name || '', value: `${option.displayvalue}${suffix}` })
  }
}
